package com.ai.bitcoin.service.impl;

import com.ai.bitcoin.common.resp.ResponseEntity;
import com.ai.bitcoin.constant.CommonConstant;
import com.ai.bitcoin.helper.HtmlReportParseHelper;
import com.ai.bitcoin.init.ThreadPoolService;
import com.ai.bitcoin.jpa.dao.BccWeixinCoinQrcodeDao;
import com.ai.bitcoin.jpa.entity.BccWeixinCoinQrcode;
import com.ai.bitcoin.redis.service.BccRedisService;
import com.ai.bitcoin.service.MakeHtmlService;
import com.ai.bitcoin.service.MemberCenterService;
import com.ai.bitcoin.util.DateUtil;
import com.ai.bitcoin.util.FileUtil;
import com.ai.bitcoin.util.JacksonUtils;
import com.ai.bitcoin.vo.HtmlReportCoinQrcodeinfoVO;
import com.ai.bitcoin.vo.HtmlReportGenerateVO;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;

@Service(value = "makeHtmlService")
@Slf4j
public class MakeHtmlServiceImpl implements MakeHtmlService {

    @Autowired
    private BccRedisService bccRedisService;

    @Value("${report.html.rootpath}")
    private String reportHtmlPath;

    @Value("${chrome.driver.location}")
    private String chromeDriverLocation;

    @Value("${report.html.visit.path}")
    private String reportHtmlVisitpath;

    @Value("${media.html.visit.path}")
    private String mediaHtmlVisitpath;

    @Value("${media.html.rootpath}")
    private String mediaHtmlPath;

    @Value("${oss.bucket.name}")
    private String bucketName;

    /**
     * ossEndpoint:阿里云文件地址
     */
    @Value("${oss.endpoint}")
    private String ossEndpoint;

    @Value("${access.id}")
    private String accessId;

    @Value("${access.key}")
    private String accessKey;

    @Value("${oss.show.file.url}")
    private String url;

    @Autowired
    private ThreadPoolService threadPoolService;

    @Autowired
    private BccWeixinCoinQrcodeDao bccWeixinCoinQrcodeDao;

    @Autowired
    WxMpService wxMpService;

    @Autowired
    private MemberCenterService memberCenterService;

    private String[] bccIds = {"1", "1026", "11", "12", "1202", "124", "1386", "1396", "141", "1449", "146", "19", "201", "235", "24", "27", "3", "31", "372", "374", "39", "4", "5", "50", "53", "57", "6", "655", "66", "7", "9", "90", "2", "10", "13", "14", "18", "17", "138", "22", "8"};

    @Async
    @Override
    public void generateMedia(String openId, Date time) {
        try {

            File file = memberCenterService.getPoster(openId);
            //上传素材
            try {
                WxMediaUploadResult result = wxMpService.getMaterialService().mediaUpload(WxConsts.MaterialType.IMAGE, file);
                if (StringUtils.isNotEmpty(result.getMediaId())) {
                    WxMpKefuMessage message = new WxMpKefuMessage();
                    message.setMediaId(result.getMediaId());
                    message.setToUser(openId);
                    message.setMsgType(WxConsts.KefuMsgType.IMAGE);
                    wxMpService.getKefuService().sendKefuMessage(message);
                }
            } catch (Exception e) {
                log.warn("发送海报异常 {}", openId);
            }

        } catch (Exception ignored) {
        }
    }

    @Override
    public void generateReport() {
        log.error("报告生成任务开始执行，{}", new Date());
        long startTime = System.currentTimeMillis();
        String reportDate = DateUtil.toDateStr(new Date(), CommonConstant.REPORT_HTML_PREFIX_PATH);
        Map<String, HtmlReportGenerateVO> data = Maps.newHashMap();
        for (String bccId : bccIds) {
            HtmlReportGenerateVO htmlReportGenerateVO = null;
            // 从redis中获取报告
            try {
                htmlReportGenerateVO = bccRedisService.getBitCoinReport("report_" + reportDate + "_" + bccId);
            } catch (Exception e) {
                log.error("deseriase fail");
                continue;
            }
            if (htmlReportGenerateVO == null) {
                log.error("【生成报告】 从redis中获取报告为空，bccId为：{}，reportDate为：{}", bccId, reportDate);
                continue;
            }
            BccWeixinCoinQrcode qrcode = bccWeixinCoinQrcodeDao.findByBccId(bccId);
            if (qrcode == null) {
                log.error("【生成报告】 从redis中获取报告为空，qrcode is null：{}，reportDate为：{}", bccId, reportDate);
                continue;
            }
            htmlReportGenerateVO.setQrcodeinfo(new HtmlReportCoinQrcodeinfoVO(qrcode.getUrl()));
            System.out.println(htmlReportGenerateVO);
            // 判断用户是否订阅
            boolean isSubscription = false;
            if (!isSubscription) {
                // 非订阅用户，（订阅部分数据）
                htmlReportGenerateVO = HtmlReportParseHelper.Subscription.partReport(htmlReportGenerateVO);
                data.put(bccId, htmlReportGenerateVO);
            }
        }

        if (data.size() <= 0) {
            log.error("数据源无数据");
            return;
        }

        Map<String, String> bccHtmls = new HashMap<>(data.size(), 1.0f);
        try {
            for (Map.Entry<String, HtmlReportGenerateVO> requestData : data.entrySet()) {
                String bccId = requestData.getKey();
                HtmlReportGenerateVO reportGenerateVO = requestData.getValue();
                InputStream is = this.getClass().getClassLoader().getResourceAsStream("./make/htmlprint/pushModule.html");
                Document document = Jsoup.parse(is, "utf-8", "");
                Elements scripts = document.select("script");
                for (Element script : scripts) {
                    if (script.html().contains("var coinWholeData")) { //注意这里一定是html(), 而不是text()

                        script.html(script.html()
                                .replace("%s1", JacksonUtils.toJson(new ResponseEntity<>(200, "success", reportGenerateVO)))
                        );
                    }
                }
                bccHtmls.put(bccId, document.toString().replace("&gt;", ">").replace("&lt;", "<").replace("&amp;", "&"));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (bccHtmls == null || bccHtmls.size() <= 0) {
            log.error("无报告生成");
            return;
        }

        //落入文件系统
        //step1 :创建今天目录
        String parentPath = DateUtil.toDateStr(new Date(), CommonConstant.REPORT_HTML_PREFIX_PATH);
        String[] directories = {parentPath};
        FileUtil.createMultilevelDirectory(directories, reportHtmlPath);
        ExecutorService htmlFilePool = threadPoolService.getHtmlFilePool();
        String prefixPath = reportHtmlPath + "/" + parentPath;
        try {
            Runtime.getRuntime().exec("chmod 777 " + prefixPath);
            log.error("赋予0777权限-{}", prefixPath);
        } catch (IOException e) {
            log.error("赋予0777权限失败，{}--{}", prefixPath, new Date());
        }
        List<String> htmlFilePaths = Lists.newArrayList();
        final CountDownLatch latch = new CountDownLatch(bccHtmls.size());
        for (Map.Entry<String, String> entry : bccHtmls.entrySet()) {
            htmlFilePool.submit(new Runnable() {
                @Override
                public void run() {
                    String bccId = entry.getKey();
                    OutputStream os = null;
                    String linkUrl = reportHtmlVisitpath + "/" + parentPath + "/" + bccId.replace("#", "") + ".html";
                    htmlFilePaths.add(linkUrl);
                    try {
                        os = new FileOutputStream(prefixPath + "/" + bccId.replace("#", "") + ".html");
                        os.write(entry.getValue().getBytes());
                        os.flush();
                        if (log.isDebugEnabled()) {
                            log.debug("file into system path--{},locate imge path--{}", prefixPath + "/" + bccId + ".html", reportHtmlVisitpath + parentPath + "/" + bccId.replace("#", "") + ".html");
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        try {
                            os.close();
                            try {
                                Runtime.getRuntime().exec("chmod 777 " + prefixPath + "/" + bccId.replace("#", "") + ".html");
                                log.error("赋予0777权限-{}", prefixPath + "/" + bccId.replace("#", "") + ".html");
                            } catch (IOException e) {
                                log.error("赋予0777权限失败，{}--{}", prefixPath + "/" + bccId.replace("#", "") + ".html", new Date());
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }

                    if (log.isDebugEnabled()) {
                        log.debug("htmlpaths文件路径path,{}", htmlFilePaths);
                    }
                    latch.countDown();
                }
            });
        }


        try {
            latch.await();
            //step3:开始截图
            if (htmlFilePaths.size() > 0) {
                ExecutorService snapShotPool = threadPoolService.getSnapShotPool();
                snapShotPool.submit(new Runnable() {
                    @Override
                    public void run() {
                        if (log.isDebugEnabled()) {
                            log.debug("html文件路径path,{}", htmlFilePaths);
                        }
                        final CountDownLatch latch1 = new CountDownLatch(htmlFilePaths.size());
                        System.setProperty("webdriver.chrome.driver", chromeDriverLocation);
                        ChromeOptions options = new ChromeOptions();
                        options.addArguments("headless");// headless mode
                        options.addArguments("disable-gpu");
                        //  options.addArguments("screenshot"); //没打开一个页面就截图
                        WebDriver driver = new ChromeDriver(options);

                        if (log.isDebugEnabled()) {
                            log.debug("html文件路径path2222after,{}", htmlFilePaths);
                        }
                        for (String htmlPath : htmlFilePaths) {
                            snapShotPool.submit(new Runnable() {
                                @Override
                                public void run() {
                                    driver.get(htmlPath);
                                    JavascriptExecutor js = (JavascriptExecutor) driver;
                                    Object s = js.executeScript("return document.body.scrollHeight");
                                    if (log.isDebugEnabled()) {
                                        log.debug("html高度为{}", JacksonUtils.toJson(s));
                                    }
                                    System.out.println();
                                    driver.manage().window().setSize(new Dimension(400, Integer.valueOf(JacksonUtils.toJson(s))));
                                    File srcFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
                                    String path = htmlPath.replace(".html", ".png").replace(reportHtmlVisitpath, reportHtmlPath);
                                    if (log.isDebugEnabled()) {
                                        log.error("image download path,{}", path);
                                    }
                                    try {
                                        FileUtils.copyFile(srcFile, new File(path));
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }
                                    try {
                                        Runtime.getRuntime().exec("chmod 777 " + path);
                                        log.error("赋予0777权限-{}", path);
                                    } catch (IOException e) {
                                        log.error("赋予0777权限失败，{}--{}", path, new Date());
                                    }
                                    latch1.countDown();
                                }
                            });
                        }
                        try {
                            latch1.await();
                            driver.quit();
                            driver.close();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
            long endTime = System.currentTimeMillis();
            float seconds = (endTime - startTime) / 1000F;
            log.error("报告任务结束执行，{}", Float.toString(seconds) + " seconds.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
